package de.tudresden.st.cbse.calendar;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

import de.tudresden.st.cbse.calendar.appointment.Appointment;
import de.tudresden.st.cbse.calendar.appointment.AppointmentType;
import de.tudresden.st.cbse.calendar.share.ResultType;
import de.tudresden.st.cbse.calendar.share.ShareResult;

@Entity
public class Calendar implements Serializable {
    private static final long serialVersionUID = 1628526407270265942L;

    @Id
    @GeneratedValue
    @SuppressWarnings("unused")
    @Column(name="CALENDAR_ID")
    private long              id;

    @ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinTable(name="CALENDAR_APPOINTMENT",
                    joinColumns= {@JoinColumn(name="CALENDAR_ID", referencedColumnName="CALENDAR_ID")},
                    inverseJoinColumns= {@JoinColumn(name="APPOINTMENT_ID", referencedColumnName="APPOINTMENT_ID")})
    private Collection<Appointment> appointments;
    
    public ShareResult check(Appointment appointment) {
        Iterable<Appointment> appointments = get(appointment.getStart(), appointment.getEnd());
        
        ShareResult result = new ShareResult(appointment, ResultType.SUCCESSFUL);
        
        for (Appointment app : appointments) {
            if (app.getType() != AppointmentType.FREE) {
                if (app.isPrivate()) {
                    result = new ShareResult(appointment, ResultType.FAILPRIVATE);
                } else {
                    result = new ShareResult(app, ResultType.FAILPUBLIC);
                }
                
                break;
            }
        }
        
        return result;
    }

    public void add(Appointment appointment) {
        appointments.add(appointment);
    }

    public Iterable<Appointment> get(Date start, Date end) {
        List<Appointment> result = new LinkedList<Appointment>();
        
        for (Appointment app : appointments) {
            if ( (app.getStart().after(start) && app.getStart().before(end)) || // start within the given time span 
                 (app.getEnd().before(end) && app.getEnd().after(start)) ||     // ends within the given time span
                 (app.getStart().before(start) && app.getEnd().after(end)) ) // starts before and ends after the given timespan
                result.add(app);
        }
        
        return result;
    }

    public Iterable<Appointment> get() {
        return appointments;
    }
}
